package jvm规范;

//Class 文件结构
●Class 类的本质
任何一个 Class 文件都对应着唯一一个类或接口的定义信息，但反过来说，Class 文件实际上它并不一定以磁盘文件形式存在。Class 文件是一组以8位字节为基础单位的二进制流

●Class 文件格式
Class 的结构不像 XML 等描述语言，由于它没有任何分隔符号。所以在其中的数据项，无论是字节顺序还是数量，都是被严格限定的，哪个字节代表什么含义，长度是多少，先后顺序
如何，都不允许改变

Class 文件格式采用一种类似于 C 语言结构体的方式进行数据存储，这种结构中只有两种数据类型：无符号数和表

1.无符号数属于基本的数据类型，以 u1、u2、u4、u8 来分别代表1个字节、2个字节、4个字节、8个字节的无符号数，无符号数可以用来描述数字、索引引用、数量值或者按
照 UTF-8 编码构成字符串值
2.表是由多个无符号数或者其他表作为数据项构成的复合数据类型，所有表都习惯性地以"_info"结尾。表用于描述有层次关系的复合结构的数据，整个 Class 文件本质上就
是一张表。由于表没有固定长度，所以通常会在其前面加上个数说明
3.代码举例
public class Demo1 {
    private int num = 1;

    public int add() {
        num = num + 2;
        return num;
    }
}
对应的字节码文件：
ca fe ba be 00 00 00 3c 00 13 0a 00 02 00 03 07 
00 04 0c 00 05 00 06 01 00 10 6a 61 76 61 2f 6c 
61 6e 67 2f 4f 62 6a 65 63 74 01 00 06 3c 69 6e 
69 74 3e 01 00 03 28 29 56 09 00 08 00 09 07 00 
0a 0c 00 0b 00 0c 01 00 05 44 65 6d 6f 31 01 00 
03 6e 75 6d 01 00 01 49 01 00 04 43 6f 64 65 01 
00 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 
65 01 00 03 61 64 64 01 00 03 28 29 49 01 00 0a 
53 6f 75 72 63 65 46 69 6c 65 01 00 0a 64 65 6d 
6f 31 2e 6a 61 76 61 00 21 00 08 00 02 00 00 00 
01 00 02 00 0b 00 0c 00 00 00 02 00 01 00 05 00 
06 00 01 00 0d 00 00 00 26 00 02 00 01 00 00 00 
0a 2a b7 00 01 2a 04 b5 00 07 b1 00 00 00 01 00 
0e 00 00 00 0a 00 02 00 00 00 01 00 04 00 02 00 
01 00 0f 00 10 00 01 00 0d 00 00 00 2b 00 03 00 
01 00 00 00 0f 2a 2a b4 00 07 05 60 b5 00 07 2a 
b4 00 07 ac 00 00 00 01 00 0e 00 00 00 0a 00 02 
00 00 00 05 00 0a 00 06 00 01 00 11 00 00 00 02 
00 12 ca fe ba be 00 00 00 3c 00 13 0a 00 02 00 
03 07 00 04 0c 00 05 00 06 01 00 10 6a 61 76 61 
2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 01 00 06 3c 
69 6e 69 74 3e 01 00 03 28 29 56 09 00 08 00 09 
07 00 0a 0c 00 0b 00 0c 01 00 05 44 65 6d 6f 31 
01 00 03 6e 75 6d 01 00 01 49 01 00 04 43 6f 64 
65 01 00 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 
62 6c 65 01 00 03 61 64 64 01 00 03 28 29 49 01 
00 0a 53 6f 75 72 63 65 46 69 6c 65 01 00 0a 64 
65 6d 6f 31 2e 6a 61 76 61 00 21 00 08 00 02 00 
00 00 01 00 02 00 0b 00 0c 00 00 00 02 00 01 00 
05 00 06 00 01 00 0d 00 00 00 26 00 02 00 01 00 
00 00 0a 2a b7 00 01 2a 04 b5 00 07 b1 00 00 00 
01 00 0e 00 00 00 0a 00 02 00 00 00 01 00 04 00 
02 00 01 00 0f 00 10 00 01 00 0d 00 00 00 2b 00 
03 00 01 00 00 00 0f 2a 2a b4 00 07 05 60 b5 00 
07 2a b4 00 07 ac 00 00 00 01 00 0e 00 00 00 0a 
00 02 00 00 00 05 00 0a 00 06 00 01 00 11 00 00 
00 02 00 12

换句话说，充分理解了每一个字节码文件的细节，自己也可以反编译出 Java 源文件来

●Class 文件结构概述
Class 文件的结构并不是一成不变的，随着 Java 虚拟机的不断发展，总是不可避免地会对 Class 文件结构做出一些调整，但是其基本结构和框架是非常稳定的

Class 文件的总体结构如下：

1.魔数
2.Class 文件版本
3.常量池
4.访问标志
5.类索引、父类索引、接口索引集合
6.字段表集合
7.方法表集合
8.属性表集合

u4              magic;
u2              minor_version;
u2              major_version;
u2              constant_pool_count;
cp_info         constant_pool[constant_pool_count-1];
u2              access_flags;
u2              this_class;
u2              super_class;
u2              interfaces_count;
u2              interfaces[interfaces_count];
u2              fields_count;
field_info      fields[fields_count];
u2              methods_count;
method_info     methods[methods_count];
u2              attributes_count;
attribute_info  attributes[attributes_count];

●魔数：Class 文件的标志
Magic Number(魔数)

每个 Class 文件开头的4个字节的无符号整数称为魔数(Magic Number)
它的唯一作用是确定这个文件是否为一个能被虚拟机接受的有效合法的 Class 文件。即：魔数是 Class 文件的标识符
魔数值固定为 0xCAFEBABE。不会改变
如果一个 Class 文件不以 0xCAFEBABE 开头，虚拟机在进行文件校验的时候就会直接抛出以下错误：
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 1885430635 in class file StringTest
使用魔数而不是扩展名来进行识别主要是基于安全方面的考虑，因为文件扩展名可以随意地改动
Class 文件版本号
紧接着魔数的4个字节存储的是 Class 文件的版本号。同样也是4个字节。第5个和第6个字节所代表的含义就是编译的副版本号 minor_version，而第7个和第8个字节就是编译的主版本号 major_version
它们共同构成了 Class 文件的格式版本号。譬如某个 Class 文件的主版本号为 M，服版本号为 m，那么这个 Class 文件的格式版本号就确定为 M.m
版本号和 Java 编译器的对应关系如下表：

下表列出了各个版本 JDK 的十六进制版本号信息：
JDK版本      次版本号     主版本号     十进制
JDK1.1        3        002C        45
JDK1.2      0000       002E        46
JDK1.3      0000       002F        47
JDK1.4      0000       0030        48
JDK1.5      0000       0031        49
JDK1.6      0000       0032        50
JDK1.7      0000       0033        51
JDK1.8      0000       0034        52
JDK1.9      0000       0035        53
JDK1.10     0000       0036        54
JDK1.11     0000       0037        55

Java 的版本号是从45开始的，JDK 1.1 之后的每个 JDK 大版本发布主版本号向上加1
不同版本的 Java 编译器编译的 Class 文件对应的版本是不一样的。目前，高版本的 Java 虚拟机可以执行由低版本编译器生成的 Class 文件，但是低版本的 Java 虚拟机不能执
行由高版本编译器生成的 Class 文件。否则 JVM 会抛出 java.lang.UnsupportedClassVersionError 异常(向下兼容)
在实际应用中，由于开发环境和生产环境的不同，可能会导致该问题的发生。因此，需要我们在开发时，特别注意开发编译的 JDK 版本和生产环境的 JDK 版本是否一致
虚拟机 JDK 版本为 1.k (k >= 2)时，对应的 Class 文件格式版本号的范围为 45.0 - 44 + k.0(含两端)

●常量池：存放所有常量

